// ==============================================================================================
// ╦  ┬┌─┐┌─┐┌┐┌┌─┐┌─┐    Yaksha Programming Language
// ║  ││  ├┤ │││└─┐├┤     is Licensed with GPLv3 + extra terms. Please see below.
// ╩═╝┴└─┘└─┘┘└┘└─┘└─┘
// Note: libs - MIT license, runtime/3rd - various
// ==============================================================================================
// GPLv3:
//
// Yaksha - Programming Language.
// Copyright (C) 2020 - 2024 Bhathiya Perera
//
// This program is free software: you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program.
// If not, see https://www.gnu.org/licenses/.
//
// ==============================================================================================
// Additional Terms:
//
// Please note that any commercial use of the programming language's compiler source code
// (everything except compiler/runtime, compiler/libs and compiler/3rd) require a written agreement
// with author of the language (Bhathiya Perera).
//
// If you are using it for an open source project, please give credits.
// Your own project must use GPLv3 license with these additional terms.
//
// You may use programs written in Yaksha/YakshaLisp for any legal purpose
// (commercial, open-source, closed-source, etc) as long as it agrees
// to the licenses of linked runtime libraries (see compiler/runtime/README.md).
//
// ==============================================================================================
// ast.h
// generated by update_ast.py
#ifndef AST_H
#define AST_H
#include "tokenizer/token.h"
#include "utilities/annotations.h"
#include "utilities/ykdatatype.h"
#include <vector>
namespace yaksha {
  // ------ forward declarations ------
  struct expr;
  struct stmt;
  struct parameter;
  struct name_val;
  struct assign_expr;
  struct assign_arr_expr;
  struct assign_member_expr;
  struct binary_expr;
  struct curly_call_expr;
  struct fncall_expr;
  struct get_expr;
  struct grouping_expr;
  struct literal_expr;
  struct logical_expr;
  struct macro_call_expr;
  struct set_expr;
  struct square_bracket_access_expr;
  struct square_bracket_set_expr;
  struct unary_expr;
  struct variable_expr;
  struct block_stmt;
  struct break_stmt;
  struct ccode_stmt;
  struct cfor_stmt;
  struct class_stmt;
  struct compins_stmt;
  struct const_stmt;
  struct continue_stmt;
  struct def_stmt;
  struct defer_stmt;
  struct del_stmt;
  struct directive_stmt;
  struct dsl_macro_stmt;
  struct elif_stmt;
  struct enum_stmt;
  struct expression_stmt;
  struct foreach_stmt;
  struct forendless_stmt;
  struct if_stmt;
  struct import_stmt;
  struct let_stmt;
  struct macros_stmt;
  struct nativeconst_stmt;
  struct pass_stmt;
  struct return_stmt;
  struct runtimefeature_stmt;
  struct token_soup_stmt;
  struct union_stmt;
  struct while_stmt;
  // Types of expressions and statements
  enum class ast_type {
    EXPR_ASSIGN,
    EXPR_ASSIGN_ARR,
    EXPR_ASSIGN_MEMBER,
    EXPR_BINARY,
    EXPR_CURLY_CALL,
    EXPR_FNCALL,
    EXPR_GET,
    EXPR_GROUPING,
    EXPR_LITERAL,
    EXPR_LOGICAL,
    EXPR_MACRO_CALL,
    EXPR_SET,
    EXPR_SQUARE_BRACKET_ACCESS,
    EXPR_SQUARE_BRACKET_SET,
    EXPR_UNARY,
    EXPR_VARIABLE,
    STMT_BLOCK,
    STMT_BREAK,
    STMT_CCODE,
    STMT_CFOR,
    STMT_CLASS,
    STMT_COMPINS,
    STMT_CONST,
    STMT_CONTINUE,
    STMT_DEF,
    STMT_DEFER,
    STMT_DEL,
    STMT_DIRECTIVE,
    STMT_DSL_MACRO,
    STMT_ELIF,
    STMT_ENUM,
    STMT_EXPRESSION,
    STMT_FOREACH,
    STMT_FORENDLESS,
    STMT_IF,
    STMT_IMPORT,
    STMT_LET,
    STMT_MACROS,
    STMT_NATIVECONST,
    STMT_PASS,
    STMT_RETURN,
    STMT_RUNTIMEFEATURE,
    STMT_TOKEN_SOUP,
    STMT_UNION,
    STMT_WHILE
  };
  // ------ expression visitor ------
  struct expr_visitor {
    virtual void visit_assign_expr(assign_expr *obj) = 0;
    virtual void visit_assign_arr_expr(assign_arr_expr *obj) = 0;
    virtual void visit_assign_member_expr(assign_member_expr *obj) = 0;
    virtual void visit_binary_expr(binary_expr *obj) = 0;
    virtual void visit_curly_call_expr(curly_call_expr *obj) = 0;
    virtual void visit_fncall_expr(fncall_expr *obj) = 0;
    virtual void visit_get_expr(get_expr *obj) = 0;
    virtual void visit_grouping_expr(grouping_expr *obj) = 0;
    virtual void visit_literal_expr(literal_expr *obj) = 0;
    virtual void visit_logical_expr(logical_expr *obj) = 0;
    virtual void visit_macro_call_expr(macro_call_expr *obj) = 0;
    virtual void visit_set_expr(set_expr *obj) = 0;
    virtual void
    visit_square_bracket_access_expr(square_bracket_access_expr *obj) = 0;
    virtual void
    visit_square_bracket_set_expr(square_bracket_set_expr *obj) = 0;
    virtual void visit_unary_expr(unary_expr *obj) = 0;
    virtual void visit_variable_expr(variable_expr *obj) = 0;
    virtual ~expr_visitor() = default;
  };
  // ------ statement visitor ------
  struct stmt_visitor {
    virtual void visit_block_stmt(block_stmt *obj) = 0;
    virtual void visit_break_stmt(break_stmt *obj) = 0;
    virtual void visit_ccode_stmt(ccode_stmt *obj) = 0;
    virtual void visit_cfor_stmt(cfor_stmt *obj) = 0;
    virtual void visit_class_stmt(class_stmt *obj) = 0;
    virtual void visit_compins_stmt(compins_stmt *obj) = 0;
    virtual void visit_const_stmt(const_stmt *obj) = 0;
    virtual void visit_continue_stmt(continue_stmt *obj) = 0;
    virtual void visit_def_stmt(def_stmt *obj) = 0;
    virtual void visit_defer_stmt(defer_stmt *obj) = 0;
    virtual void visit_del_stmt(del_stmt *obj) = 0;
    virtual void visit_directive_stmt(directive_stmt *obj) = 0;
    virtual void visit_enum_stmt(enum_stmt *obj) = 0;
    virtual void visit_expression_stmt(expression_stmt *obj) = 0;
    virtual void visit_foreach_stmt(foreach_stmt *obj) = 0;
    virtual void visit_forendless_stmt(forendless_stmt *obj) = 0;
    virtual void visit_if_stmt(if_stmt *obj) = 0;
    virtual void visit_import_stmt(import_stmt *obj) = 0;
    virtual void visit_let_stmt(let_stmt *obj) = 0;
    virtual void visit_nativeconst_stmt(nativeconst_stmt *obj) = 0;
    virtual void visit_pass_stmt(pass_stmt *obj) = 0;
    virtual void visit_return_stmt(return_stmt *obj) = 0;
    virtual void visit_runtimefeature_stmt(runtimefeature_stmt *obj) = 0;
    virtual void visit_union_stmt(union_stmt *obj) = 0;
    virtual void visit_while_stmt(while_stmt *obj) = 0;
    virtual ~stmt_visitor() = default;
  };
  // ------ expression base class ------
  struct expr {
    virtual ~expr() = default;
    virtual void accept(expr_visitor *v) = 0;
    virtual ast_type get_type() = 0;
    virtual token *locate() = 0;
    size_t hits_{0};
  };
  // ------- statement base class ------
  struct stmt {
    virtual ~stmt() = default;
    virtual void accept(stmt_visitor *v) = 0;
    virtual ast_type get_type() = 0;
    virtual token *locate() = 0;
    size_t hits_{0};
  };
  // ------- expressions ------
  struct assign_expr : expr {
    assign_expr(token *name, token *opr, expr *right, bool promoted,
                ykdatatype *promoted_data_type);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    token *opr_;
    expr *right_;
    bool promoted_;
    ykdatatype *promoted_data_type_;
  };
  struct assign_arr_expr : expr {
    assign_arr_expr(expr *assign_oper, token *opr, expr *right);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *assign_oper_;
    token *opr_;
    expr *right_;
  };
  struct assign_member_expr : expr {
    assign_member_expr(expr *set_oper, token *opr, expr *right);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *set_oper_;
    token *opr_;
    expr *right_;
  };
  struct binary_expr : expr {
    binary_expr(expr *left, token *opr, expr *right);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *left_;
    token *opr_;
    expr *right_;
  };
  struct curly_call_expr : expr {
    curly_call_expr(expr *dt_expr, token *curly_open,
                    std::vector<name_val> values, token *curly_close);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *dt_expr_;
    token *curly_open_;
    std::vector<name_val> values_;
    token *curly_close_;
  };
  struct fncall_expr : expr {
    fncall_expr(expr *name, token *paren_token, std::vector<expr *> args);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *name_;
    token *paren_token_;
    std::vector<expr *> args_;
  };
  struct get_expr : expr {
    get_expr(expr *lhs, token *dot, token *item);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *lhs_;
    token *dot_;
    token *item_;
  };
  struct grouping_expr : expr {
    explicit grouping_expr(expr *expression);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *expression_;
  };
  struct literal_expr : expr {
    explicit literal_expr(token *literal_token);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *literal_token_;
  };
  struct logical_expr : expr {
    logical_expr(expr *left, token *opr, expr *right);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *left_;
    token *opr_;
    expr *right_;
  };
  struct macro_call_expr : expr {
    macro_call_expr(token *path, token *name, token *not_symbol_tok,
                    token *paren_token, std::vector<expr *> args,
                    token *close_paren_token);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *path_;
    token *name_;
    token *not_symbol_tok_;
    token *paren_token_;
    std::vector<expr *> args_;
    token *close_paren_token_;
  };
  struct set_expr : expr {
    set_expr(expr *lhs, token *dot, token *item);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *lhs_;
    token *dot_;
    token *item_;
  };
  struct square_bracket_access_expr : expr {
    square_bracket_access_expr(expr *name, token *sqb_token, expr *index_expr);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *name_;
    token *sqb_token_;
    expr *index_expr_;
  };
  struct square_bracket_set_expr : expr {
    square_bracket_set_expr(expr *name, token *sqb_token, expr *index_expr);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *name_;
    token *sqb_token_;
    expr *index_expr_;
  };
  struct unary_expr : expr {
    unary_expr(token *opr, expr *right);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *opr_;
    expr *right_;
  };
  struct variable_expr : expr {
    explicit variable_expr(token *name);
    void accept(expr_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
  };
  // ------- statements ------
  struct block_stmt : stmt {
    explicit block_stmt(std::vector<stmt *> statements);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    std::vector<stmt *> statements_;
  };
  struct break_stmt : stmt {
    explicit break_stmt(token *break_token);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *break_token_;
  };
  struct ccode_stmt : stmt {
    ccode_stmt(token *ccode_keyword, token *code_str);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *ccode_keyword_;
    token *code_str_;
  };
  struct cfor_stmt : stmt {
    cfor_stmt(token *for_keyword, token *open_paren, expr *init_expr,
              token *semi1, expr *comparison, token *semi2, expr *operation,
              token *close_paren, stmt *for_body);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *for_keyword_;
    token *open_paren_;
    expr *init_expr_;
    token *semi1_;
    expr *comparison_;
    token *semi2_;
    expr *operation_;
    token *close_paren_;
    stmt *for_body_;
  };
  struct class_stmt : stmt {
    class_stmt(token *name, std::vector<parameter> members,
               annotations annotations);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    std::vector<parameter> members_;
    annotations annotations_;
  };
  struct compins_stmt : stmt {
    compins_stmt(token *name, ykdatatype *data_type, token *meta1,
                 ykdatatype *meta2, void *meta3);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    ykdatatype *data_type_;
    token *meta1_;
    ykdatatype *meta2_;
    void *meta3_;
  };
  struct const_stmt : stmt {
    const_stmt(token *name, ykdatatype *data_type, expr *expression,
               bool is_global);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    ykdatatype *data_type_;
    expr *expression_;
    bool is_global_;
  };
  struct continue_stmt : stmt {
    explicit continue_stmt(token *continue_token);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *continue_token_;
  };
  struct def_stmt : stmt {
    def_stmt(token *name, std::vector<parameter> params, stmt *function_body,
             ykdatatype *return_type, annotations annotations);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    std::vector<parameter> params_;
    stmt *function_body_;
    ykdatatype *return_type_;
    annotations annotations_;
  };
  struct defer_stmt : stmt {
    defer_stmt(token *defer_keyword, expr *expression, stmt *del_statement);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *defer_keyword_;
    expr *expression_;
    stmt *del_statement_;
  };
  struct del_stmt : stmt {
    del_stmt(token *del_keyword, expr *expression);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *del_keyword_;
    expr *expression_;
  };
  struct directive_stmt : stmt {
    directive_stmt(token *directive_token, std::vector<parameter> values,
                   token *directive_type, token *directive_val);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *directive_token_;
    std::vector<parameter> values_;
    token *directive_type_;
    token *directive_val_;
  };
  struct dsl_macro_stmt : stmt {
    dsl_macro_stmt(token *name, token *name2, token *not_symbol_tok,
                   token *curly_open, std::vector<token *> internal_soup,
                   token *curly_close);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    token *name2_;
    token *not_symbol_tok_;
    token *curly_open_;
    std::vector<token *> internal_soup_;
    token *curly_close_;
  };
  struct elif_stmt : stmt {
    elif_stmt(token *elif_keyword, expr *expression, stmt *elif_branch);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *elif_keyword_;
    expr *expression_;
    stmt *elif_branch_;
  };
  struct enum_stmt : stmt {
    enum_stmt(token *name, std::vector<parameter> members,
              annotations annotations);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    std::vector<parameter> members_;
    annotations annotations_;
  };
  struct expression_stmt : stmt {
    explicit expression_stmt(expr *expression);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    expr *expression_;
  };
  struct foreach_stmt : stmt {
    foreach_stmt(token *for_keyword, token *name, ykdatatype *data_type,
                 token *in_keyword, expr *expression, stmt *for_body,
                 ykdatatype *expr_datatype);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *for_keyword_;
    token *name_;
    ykdatatype *data_type_;
    token *in_keyword_;
    expr *expression_;
    stmt *for_body_;
    ykdatatype *expr_datatype_;
  };
  struct forendless_stmt : stmt {
    forendless_stmt(token *for_keyword, stmt *for_body);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *for_keyword_;
    stmt *for_body_;
  };
  struct if_stmt : stmt {
    if_stmt(token *if_keyword, expr *expression, stmt *if_branch,
            token *else_keyword, stmt *else_branch);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *if_keyword_;
    expr *expression_;
    stmt *if_branch_;
    token *else_keyword_;
    stmt *else_branch_;
  };
  struct import_stmt : stmt {
    import_stmt(token *import_token, std::vector<token *> import_names,
                token *name, file_info *data);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *import_token_;
    std::vector<token *> import_names_;
    token *name_;
    file_info *data_;
  };
  struct let_stmt : stmt {
    let_stmt(token *name, ykdatatype *data_type, expr *expression);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    ykdatatype *data_type_;
    expr *expression_;
  };
  struct macros_stmt : stmt {
    macros_stmt(token *macros_token, token *not_symbol_tok, token *curly_open,
                std::vector<token *> lisp_code, token *curly_close);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *macros_token_;
    token *not_symbol_tok_;
    token *curly_open_;
    std::vector<token *> lisp_code_;
    token *curly_close_;
  };
  struct nativeconst_stmt : stmt {
    nativeconst_stmt(token *name, ykdatatype *data_type, token *ccode_keyword,
                     token *code_str, bool is_global);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    ykdatatype *data_type_;
    token *ccode_keyword_;
    token *code_str_;
    bool is_global_;
  };
  struct pass_stmt : stmt {
    explicit pass_stmt(token *pass_token);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *pass_token_;
  };
  struct return_stmt : stmt {
    return_stmt(token *return_keyword, expr *expression,
                ykdatatype *result_type);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *return_keyword_;
    expr *expression_;
    ykdatatype *result_type_;
  };
  struct runtimefeature_stmt : stmt {
    runtimefeature_stmt(token *runtimefeature_token, token *feature);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *runtimefeature_token_;
    token *feature_;
  };
  struct token_soup_stmt : stmt {
    explicit token_soup_stmt(std::vector<token *> soup);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    std::vector<token *> soup_;
  };
  struct union_stmt : stmt {
    union_stmt(token *name, std::vector<parameter> members,
               annotations annotations);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *name_;
    std::vector<parameter> members_;
    annotations annotations_;
  };
  struct while_stmt : stmt {
    while_stmt(token *while_keyword, expr *expression, stmt *while_body);
    void accept(stmt_visitor *v) override;
    ast_type get_type() override;
    token *locate() override;
    token *while_keyword_;
    expr *expression_;
    stmt *while_body_;
  };
  // ------- utils ------
  struct ast_pool {
    ast_pool();
    ~ast_pool();
    expr *c_assign_expr(token *name, token *opr, expr *right, bool promoted,
                        ykdatatype *promoted_data_type);
    expr *c_assign_arr_expr(expr *assign_oper, token *opr, expr *right);
    expr *c_assign_member_expr(expr *set_oper, token *opr, expr *right);
    expr *c_binary_expr(expr *left, token *opr, expr *right);
    expr *c_curly_call_expr(expr *dt_expr, token *curly_open,
                            std::vector<name_val> values, token *curly_close);
    expr *c_fncall_expr(expr *name, token *paren_token,
                        std::vector<expr *> args);
    expr *c_get_expr(expr *lhs, token *dot, token *item);
    expr *c_grouping_expr(expr *expression);
    expr *c_literal_expr(token *literal_token);
    expr *c_logical_expr(expr *left, token *opr, expr *right);
    expr *c_macro_call_expr(token *path, token *name, token *not_symbol_tok,
                            token *paren_token, std::vector<expr *> args,
                            token *close_paren_token);
    expr *c_set_expr(expr *lhs, token *dot, token *item);
    expr *c_square_bracket_access_expr(expr *name, token *sqb_token,
                                       expr *index_expr);
    expr *c_square_bracket_set_expr(expr *name, token *sqb_token,
                                    expr *index_expr);
    expr *c_unary_expr(token *opr, expr *right);
    expr *c_variable_expr(token *name);
    stmt *c_block_stmt(std::vector<stmt *> statements);
    stmt *c_break_stmt(token *break_token);
    stmt *c_ccode_stmt(token *ccode_keyword, token *code_str);
    stmt *c_cfor_stmt(token *for_keyword, token *open_paren, expr *init_expr,
                      token *semi1, expr *comparison, token *semi2,
                      expr *operation, token *close_paren, stmt *for_body);
    stmt *c_class_stmt(token *name, std::vector<parameter> members,
                       annotations annotations);
    stmt *c_compins_stmt(token *name, ykdatatype *data_type, token *meta1,
                         ykdatatype *meta2, void *meta3);
    stmt *c_const_stmt(token *name, ykdatatype *data_type, expr *expression,
                       bool is_global);
    stmt *c_continue_stmt(token *continue_token);
    stmt *c_def_stmt(token *name, std::vector<parameter> params,
                     stmt *function_body, ykdatatype *return_type,
                     annotations annotations);
    stmt *c_defer_stmt(token *defer_keyword, expr *expression,
                       stmt *del_statement);
    stmt *c_del_stmt(token *del_keyword, expr *expression);
    stmt *c_directive_stmt(token *directive_token,
                           std::vector<parameter> values, token *directive_type,
                           token *directive_val);
    stmt *c_dsl_macro_stmt(token *name, token *name2, token *not_symbol_tok,
                           token *curly_open,
                           std::vector<token *> internal_soup,
                           token *curly_close);
    stmt *c_elif_stmt(token *elif_keyword, expr *expression, stmt *elif_branch);
    stmt *c_enum_stmt(token *name, std::vector<parameter> members,
                      annotations annotations);
    stmt *c_expression_stmt(expr *expression);
    stmt *c_foreach_stmt(token *for_keyword, token *name, ykdatatype *data_type,
                         token *in_keyword, expr *expression, stmt *for_body,
                         ykdatatype *expr_datatype);
    stmt *c_forendless_stmt(token *for_keyword, stmt *for_body);
    stmt *c_if_stmt(token *if_keyword, expr *expression, stmt *if_branch,
                    token *else_keyword, stmt *else_branch);
    stmt *c_import_stmt(token *import_token, std::vector<token *> import_names,
                        token *name, file_info *data);
    stmt *c_let_stmt(token *name, ykdatatype *data_type, expr *expression);
    stmt *c_macros_stmt(token *macros_token, token *not_symbol_tok,
                        token *curly_open, std::vector<token *> lisp_code,
                        token *curly_close);
    stmt *c_nativeconst_stmt(token *name, ykdatatype *data_type,
                             token *ccode_keyword, token *code_str,
                             bool is_global);
    stmt *c_pass_stmt(token *pass_token);
    stmt *c_return_stmt(token *return_keyword, expr *expression,
                        ykdatatype *result_type);
    stmt *c_runtimefeature_stmt(token *runtimefeature_token, token *feature);
    stmt *c_token_soup_stmt(std::vector<token *> soup);
    stmt *c_union_stmt(token *name, std::vector<parameter> members,
                       annotations annotations);
    stmt *c_while_stmt(token *while_keyword, expr *expression,
                       stmt *while_body);

private:
    std::vector<expr *> cleanup_expr_;
    std::vector<stmt *> cleanup_stmt_;
  };
  /**
* Parameter for a user defined function declaration
*/
  struct parameter {
    token *name_;
    ykdatatype *data_type_;
    token *enum_val_override_;
  };
  /**
* Name + value item
*/
  struct name_val {
    token *name_;
    expr *value_;
  };
}// namespace yaksha
#endif